<?php

namespace App\Services;

use App\AwardAndExpertGroupRelations;
use App\Project;
use App\AwardApplicationFormData;
use App\AwardGroupAndExpertGroupRelations;
use App\ExpertAndExpertGroupRelations;
use App\ExpertGroup;
use App\WorkflowPhase;
use Auth, DB;
use App\User;
use phpseclib\Crypt\RSA;

class AuthService
{
    public function canUserAccessProject(User $user, Project $application)
    {
        if ($user->isAdmin()) {
            return true;
        }
        if ($user->isStaff()) {
            return true;
        }
        if ($user->isCommittee()) {
            return true;
        }
        if ($user->isReviewer()) {
            return true;
        }
        if ($user->isMeetingReviewer()) {
            return true;
        }
        if ($user->isApplicant() && $user->id === $application->user_id) {
            return true;
        }
        if ($user->isNominator()) {
            $row = DB::table('nomination_requests')
                ->where('nominator_id', $user->id)
                ->where('application_id', $application->id)
                ->first();
            if ($row) {
                return true;
            }
        }
        return false;
    }

    public function canUserEditAwardApplication(User $user, Project $project)
    {
        if ($user->isAdmin()) {
            return true;
        }

        /**
         * @edit
         * @需求：申报阶段关闭后仅 退回修改的可以继续修改提交
         * @start
         */

//        $applicationEnabled = config('app.award_application_enabled');
//        if ($applicationEnabled) {
//            $editableStatusIds = [Project::STATUS_FORMAL_REVIEW_FILL_APPLICATION, Project::STATUS_FORMAL_REVIEW_RETURNED_TO_FILL];
//        } else {
//            $editableStatusIds = [Project::STATUS_FORMAL_REVIEW_RETURNED_TO_FILL];
//        }
//
        $awardSvc = new AwardService();
        $applicationOpenAwardIds = $awardSvc->getApplicationOpenAwardIds();
        if (in_array($project->award_id, $applicationOpenAwardIds)) {
            $editableStatusIds = [Project::STATUS_FORMAL_REVIEW_FILL_APPLICATION, Project::STATUS_FORMAL_REVIEW_RETURNED_TO_FILL];
        } else {
            $editableStatusIds = [Project::STATUS_FORMAL_REVIEW_RETURNED_TO_FILL];
        }

        //查询是否结束形式审查 结束形式审查只能查看
//        $workflowSvc = new WorkflowService();
//        $atPhaseFormalReview = $workflowSvc->atPhase(WorkflowService::PHASE_FORMAL_REVIEW);
        /**
         * @end
         */


        if ($user->isApplicant()
//            && $atPhaseFormalReview
            && $user->id === $project->user_id
            && in_array($project->status_id, $editableStatusIds)) {
            return true;
        }
        if ($user->isNominator()) {
            $row = DB::table('nomination_requests')
                ->where('nominator_id', $user->id)
                ->where('application_id', $project->id)
                ->first();
            if ($row) {
                return true;
            }
        }
        return false;
    }

    public function getUserByEmail($email, $excludeSelf = false, $selfId = null)
    {
        if ($excludeSelf) {
            $user = User::where('id', '<>', $selfId)->where('email', $email)->first();
        } else {
            $user = User::where('email', $email)->first();
        }
        return $user;
    }

    public function getUserByUsername($username, $excludeSelf = false, $selfId = null)
    {
        if ($excludeSelf) {
            $user = User::where('id', '<>', $selfId)->where('username', $username)->first();
        } else {
            $user = User::where('username', $username)->first();
        }
        return $user;
    }

    public function getOrgCertifyUser($q = null)
    {
        if (empty($q)) {
            $query = User::where('entity_type', 'org')->where('org_certify_status', 'certifying');
        } else {
            $query = User::where('username', 'like', '%' . $q . '%')
                ->orWhere('email', 'like', '%' . $q . '%')
                ->orWhere('name', 'like', '%' . $q . '%')
                ->orWhere('tel', 'like', '%' . $q . '%')
                ->orWhere('org_contact', 'like', '%' . $q . '%');
        }
        $orgUsers = $query->where('entity_type', 'org')->where('org_certify_status', 'certifying')->get();
        return $orgUsers;
    }

    public function getUserByRolesUsernamePassword($roles, $username, $password)
    {
        /** @var User $user */
        $user = User::where('username', $username)
            ->where('password', $password)
            ->first();
        if (empty($user)) {
            return null;
        }

        $roleMatch = false;
        if ($user->isApplicant() && in_array('applicant', $roles)) {
            $roleMatch = true;
        }
        if ($user->isNominator() && in_array('nominator', $roles)) {
            $roleMatch = true;
        }
        if ($user->isReviewer() && in_array('reviewer', $roles)) {
            $roleMatch = true;
        }
        if ($user->isMeetingReviewer() && in_array('meeting_reviewer', $roles)) {
            $roleMatch = true;
        }
        if ($user->isCommittee() && in_array('committee', $roles)) {
            $roleMatch = true;
        }

        if ($user->isAdmin() && in_array('admin', $roles)) {
            $roleMatch = true;
        }

        /**
         * @修改 工作人员登入后台
         * @time 2020-06-05
         * @start
         */
        if ($user->isStaff() && in_array('staff', $roles)) {
            $roleMatch = true;
        }
        /**
         * @end
         */

        if ($roleMatch) {
            return $user;
        }
        return null;
    }

    public function createPersonalApplicant($username, $email, $password, $name, $tel, $workOrgName, $adminAdd)
    {
        $user = new User;
        $user->is_applicant = 1;
        $user->entity_type = 'personal';
        $user->username = $username;
        $user->email = $email;
        $user->password = $password;
        $user->name = $name;
        $user->tel = $tel;
        $user->work_org_name = $workOrgName;
        $user->save();
        return $user;
    }

    public function createOrgApplicant($username, $email, $password, $name, $orgBusinessLicensePhoto, $orgContact, $tel, $adminAdd)
    {
        $user = new User;
        $user->is_applicant = 1;
        $user->entity_type = 'org';
        $user->org_certify_status = $adminAdd ? 'certified' : 'certifying';
        $user->username = $username;
        $user->email = $email;
        $user->password = $password;
        $user->name = $name;
        $user->org_biz_lic_photo = $orgBusinessLicensePhoto;
        $user->org_contact = $orgContact;
        $user->tel = $tel;
        $user->save();
        return $user;
    }

    public function checkUsernameFormat($username)
    {
        if (empty($username)) {
            return false;
        }
        $len = strlen($username);
        if ($len < 3 || $len > 16) {
            return false;
        }
        return true;
    }

    public function checkPasswordFormat($password)
    {
        if (empty($password)) {
            return false;
        }
        $len = strlen($password);
        if ($len < 8 || $len > 16) {
            return false;
        }
        return true;
    }

    public function decryptClientPassword($encryptedPasswordBase64)
    {
        $privateKeyBase64 = config('vars.rsa_priv_key');
        $rsa = new RSA();
        $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
        $rsa->loadKey($privateKeyBase64);
        $plainPassword = $rsa->decrypt(base64_decode($encryptedPasswordBase64));
        return $plainPassword;
    }

    public function resetUserPassword(User $user, $password)
    {
        $user->password = $password;
        $user->save();
    }

    public function logout()
    {
        Auth::logout();
    }

    // By Fangzheng
    public function changeOrgUsersCertifyStatus(User $user, $status)
    {
        $certifyStatus = $status == 'pass' ? 'certified' : 'failed';
        $user->org_certify_status = $certifyStatus;
        $user->save();
    }

    // By Fangzheng
    public function canUserMangeAllUser(User $user)
    {
        if ($user->isAdmin()) {
            return true;
        }
        return $user;
    }

    // By Fangzheng
    public function getAllApplicantsInfoByAdmin()
    {
        return User::where('is_applicant', 1)->get();
    }

    // By Fangzheng
    public function changeUserOrgBizLicPhoto(User $user, $photoPath)
    {
        $user->org_biz_lic_photo = $photoPath;
        $user->org_certify_status = 'certifying';
        $user->save();
    }

    // By Fangzheng
    public function deleteUser(User $user)
    {
        $applicationIds = Project::where('user_id', $user->id)->pluck('id');
        DB::beginTransaction();
        AwardApplicationFormData::whereIn('id', $applicationIds)->delete();
        Project::where('user_id', $user->id)->delete();
        $user->delete();
        DB::commit();
    }

    // By Fangzheng
    public function checkReviewerInExpertGroup(User $user)
    {
        return ExpertAndExpertGroupRelations::where('expert_id', $user->id)->exists();
    }

    // By Fangzheng
    public function getApplicantUsersPageData($params)
    {
        $filters = json_decode($params['filters'], true);
        $q = $filters['keyword'];
        if (empty($q)) {
            $query = User::whereNotNull('id');
        } else {
            $query = User::where('username', 'like', "%$q%")
                ->orWhere('email', 'like', "%$q%")
                ->orWhere('name', 'like', "%$q%")
                ->orWhere('tel', 'like', "%$q%")
                ->orWhere('org_contact', 'like', "%$q%");
        }
        $entityTypeFilter = $filters['entityTypeFilter'];
        if ($entityTypeFilter) {
            $query->where('entity_type', $entityTypeFilter);
        }
        $query->where('is_applicant', 1);
        $sortBy = $filters['sortBy'];
        if (str_contains($sortBy, '|')) {
            $parts = explode('|', $sortBy);
            $query->orderBy($parts[0], $parts[1]);
        } else {
            $query->orderBy('created_at', 'desc');
        }
        $pageSize = $params['pageSize'];
        $pageData = $query->paginate($pageSize);
        return $pageData;
    }

    // By Fangzheng
    public function updateUserInfoByTargetInfo(User $user, $targetInfo)
    {
        $user->username = $targetInfo['username'];
        $user->email = $targetInfo['email'];
        $user->name = $targetInfo['name'];
        $user->tel = $targetInfo['tel'];
        $user->entity_type = $targetInfo['entity_type'];
        $user->org_contact = $targetInfo['org_contact'];
        $user->entity_type = $targetInfo['entity_type'];
        $user->save();
    }

    // By Fangzheng
    public function getExpertGroupByGroupName($groupName)
    {
        return ExpertGroup::where('group_name', $groupName)->first();
    }

    // By Fangzheng
    public function createExpertGroup($groupName)
    {
        $awardGroup = new ExpertGroup();
        $awardGroup->group_name = $groupName;
        $awardGroup->save();
    }

    // By Fangzheng
    public function canDeleteExpertGroup(ExpertGroup $group)
    {
        $relations = ExpertAndExpertGroupRelations::where('expert_group_id', $group->id)->get()->toArray();
        if (empty($relations)) {
            return true;
        } else {
            return false;
        }
    }

    // By Fangzheng
    public function deleteExpertGroup(ExpertGroup $group)
    {
        DB::beginTransaction();
        AwardAndExpertGroupRelations::where('expert_group_id', $group->id)->delete();
        AwardGroupAndExpertGroupRelations::where('expert_group_id', $group->id)->delete();
        ExpertAndExpertGroupRelations::where('expert_group_id', $group->id)->delete();
        $group->delete();
        DB::commit();
    }

    // By Fangzheng
    public function getExpertGroupsPageData($params)
    {
        $filters = json_decode($params['filters'], true);
        $q = $filters['keyword'];
        if (empty($q)) {
            $query = DB::table('expert_groups as A')->whereNotNull('A.id');
        } else {
            $query = DB::table('expert_groups as A')->where('A.group_name', 'like', "%$q%");
        }
        $query->leftJoin('expert_and_expert_group_relations as B', 'A.id', '=', 'B.expert_group_id')
            ->leftJoin('users as C', 'A.leader_expert_id', '=', 'C.id')
            ->groupBy('A.id', 'A.group_name', 'A.created_at', 'C.name', 'A.leader_expert_id', 'A.locked')
            ->select(DB::raw('count(B.expert_id) as totalCount, A.id, A.group_name, A.created_at, C.name as leader_name, A.leader_expert_id, A.locked'));
        $pageSize = $params['pageSize'];
        $pageData = $query->paginate($pageSize);
        return $pageData;
    }

    // By Fangzheng
    public function getCanBeAllocatedExperts($filters, $groupId)
    {
        $q = $filters['keyword'];
        if (empty($q)) {
            $query = DB::table('users as A')->where('A.is_reviewer', 1);
        } else {
            $query = DB::table('users as A')->where(function ($query) use ($q) {
                $query->where('A.is_reviewer', 1)->where('A.username', 'like', "%$q%");
            })->orWhere(function ($query) use ($q) {
                $query->where('A.is_reviewer', 1)->where('A.name', 'like', "%$q%");
            })->orWhere(function ($query) use ($q) {
                $query->where('A.is_reviewer', 1)->where('A.work_org_name', 'like', "%$q%");
            });
        }
        $isInGroupFilter = $filters['is_in_group'];
        if ($isInGroupFilter) {
            if ($isInGroupFilter == 'has') {
                $experts = $query->join('expert_and_expert_group_relations as B', 'A.id', '=', 'B.expert_id')
                    ->where('B.expert_group_id', '<>', $groupId)
                    ->select('A.id', 'A.name', 'B.expert_group_id', 'A.work_org_name')
                    ->get();
            } else {
                $experts = $query->leftJoin('expert_and_expert_group_relations as B', 'A.id', '=', 'B.expert_id')
                    ->whereNull('B.expert_group_id')
                    ->select('A.username', 'A.id', 'A.name', 'B.expert_group_id', 'A.work_org_name')
                    ->get();
            }
        } else {
            $experts = $query->leftJoin('expert_and_expert_group_relations as B', 'A.id', '=', 'B.expert_id')
                ->select('A.id', 'A.name', 'B.expert_group_id', 'A.work_org_name')
                ->get();
        }
        $experts = $experts->toArray();
        foreach ($experts as $k => $expert) {
            if ($expert->expert_group_id == $groupId) {
                //去掉了分到自己组的
                unset($experts[$k]);
            }
            $checkHasSameExpert = ExpertAndExpertGroupRelations::where('expert_group_id', $groupId)->where('expert_id', $expert->id)->first();
            if (!empty($checkHasSameExpert)) {
                unset($experts[$k]);
            }
        }
        $experts = array_values($experts);
        //去除重复的关联
        $commonSvc = new CommonService;
        $experts = $commonSvc->secondArrayUniqueByKey($experts, 'id');
        $experts = array_values($experts);
        return $experts;
    }

    // By Fangzheng
    public function getAllocatedExperts($filters, $group)
    {
        $groupId = $group->id;
        $leaderExpertId = $group->leader_expert_id;
        $q = $filters['keyword'];
        if (empty($q)) {
            $query = DB::table('users as A');
        } else {
            $query = DB::table('users as A')->where(function ($query) use ($q) {
                $query->where('A.is_reviewer', 1)->where('A.username', 'like', "%$q%");
            })->orWhere(function ($query) use ($q) {
                $query->where('A.is_reviewer', 1)->where('A.name', 'like', "%$q%");
            })->orWhere(function ($query) use ($q) {
                $query->where('A.is_reviewer', 1)->where('A.work_org_name', 'like', "%$q%");
            });
        }
        $experts = $query->join('expert_and_expert_group_relations as B', 'A.id', '=', 'B.expert_id')
            ->where('B.expert_group_id', $groupId)
            ->select('A.username', 'A.id', 'A.email', 'A.name', 'B.expert_group_id', 'A.work_org_name')
            ->get()->toArray();
        foreach ($experts as $k => $expert) {
            if ($expert->id === $leaderExpertId) {
                $tmp = $experts[$k];
                $experts[$k] = $experts[0];
                $experts[0] = $tmp;
                break;
            }
        }
        return $experts;
    }

    // By Fangzheng
    public function getExpertsByGroupId($groupId)
    {
        $applicationIds = ExpertAndExpertGroupRelations::where('expert_group_id', $groupId)->pluck('expert_id');
        return $applicationIds;
    }

    // By Fangzheng
    public function importExpertsToExpertGroup($group, $new_relations, $leaderExpertId)
    {
        DB::beginTransaction();
        if (!empty($leaderExpertId)) {
            $group->leader_expert_id = $leaderExpertId;
            $group->save();
        }
        if (!empty($new_relations)) {
            //一个专家可以分在多个组，不需要删除已经存在的分组关系
//            $changeExpertIds = array_column($new_relations, 'expert_id');
//            ExpertAndExpertGroupRelations::whereIn('expert_id', $changeExpertIds)->delete();
            ExpertAndExpertGroupRelations::insert($new_relations);
        }
        DB::commit();
    }

    // By Fangzheng
    public function deleteExpertsInExpertGroupByIds($groupId, $deleteExpertIds)
    {
        DB::beginTransaction();
        //如果删除的组员中有组长，则重置组长
        $group = ExpertGroup::find($groupId);
        if (in_array($group->leader_expert_id, $deleteExpertIds)) {
            $group->leader_expert_id = null;
            $group->save();
        }
        ExpertAndExpertGroupRelations::where('expert_group_id', $groupId)->whereIn('expert_id', $deleteExpertIds)->delete();
        DB::commit();
    }

    // By Fangzheng
    public function updateExpertBasicInfoById(ExpertGroup $group, $targetInfo)
    {
        $group->group_name = $targetInfo['group_name'];
        $group->save();
    }


}
